module dungeon.equipment;

import derelict.opengl.gl;

import nade.ast;
import nade.loader;
import nade.hud;
import nade.color;
import nade.vector;
import nade.region;
import nade.primitive;

import dungeon.game;
import dungeon.item;
import dungeon.character;
import dungeon.stats;


enum EquipmentType {
	MELEE,
	RANGED,
	AMMO,
	BODY,
	HEAD,
	HANDS,
	FEET,
	CLOAK,
	AMULET,
	RING,
}


class Equipment : Item {
	this(Game game)
	{
		super(game);

		_statsRequired = new Stats();
		_statsModified = new Stats();
	}

	real stat(uint handle)
	{
		return _statsModified[handle];
	}
	real stat(string id)
	{
		return stat(StatInfo.get(id).handle);
	}
	Stats stats()
	{
		return _statsModified;
	}

	override bool use(Character character)
	{
		character.loadout.equip(this, true);
		return true;
	}

	EquipmentType equipType() { return _equipType; }
	Stats statsRequired() { return _statsRequired; }
	Stats statsModified() { return _statsModified; }

	protected {
		EquipmentType	_equipType;
		Stats			_statsRequired;
		Stats			_statsModified;
	}

	static void install()
	{
		Loader!(Equipment).add("type",
			(ref Equipment equipment, AST ast, Object[string] state) {
				equipment._equipType = equipTypeByName(ast[0].as!string);
			}
		);
		Loader!(Equipment).add("req",
			(ref Equipment equipment, AST ast, Object[string] state) {
				equipment._statsRequired.add(ast[0].as!string, ast[1].as!real);
			}
		);
		Loader!(Equipment).add("mod",
			(ref Equipment equipment, AST ast, Object[string] state) {
				equipment._statsModified.add(ast[0].as!string, ast[1].as!real);
			}
		);
	}
}


class Loadout {
	struct Slot {
		string			name;
		EquipmentType	type;
		Equipment		item = null;
	}


	this()
	{
	}

	Equipment replace(uint index, Equipment item)
	{
		return _slots[index].item = _slots[index].item;
	}

	bool equip(Equipment item, bool force = false)
	{
		foreach(ref slot; _slots)
		{
			if(item._equipType == slot.type  &&  (force  ||  slot.item is null))
			{
				slot.item = item;
				return true;
			}
		}

		return false;
	}

	Equipment get(EquipmentType type)
	{
		foreach(slot; _slots) if(slot.type == type) return slot.item;
		return null;
	}

	real stat(uint handle)
	{
		real result = 0;
		foreach(slot; _slots) if(slot.item !is null) result += slot.item.stat(handle);
		return result;
	}
	real stat(string id)
	{
		return stat(StatInfo.get(id).handle);
	}
	Stats stats()
	{
		auto result = new Stats;
		for(uint i = 0;  i < StatInfo.count;  ++i) result[i] = stat(i);
		return result;
	}

	Slot[] slots() { return _slots; }
	Slot* slot(string name)
	{
		foreach(i, slot; _slots) if(slot.name == name) return _slots.ptr + i;
		assert(false);
	}

	protected {
		Slot[]			_slots = [
							Slot("melee", EquipmentType.MELEE),
							Slot("ranged", EquipmentType.RANGED),
							Slot("ammo", EquipmentType.AMMO),
							Slot("body", EquipmentType.BODY),
							Slot("head", EquipmentType.HEAD),
							Slot("hands", EquipmentType.HANDS),
							Slot("feet", EquipmentType.FEET),
							Slot("cloak", EquipmentType.CLOAK),
							Slot("amulet", EquipmentType.AMULET),
							Slot("ring_left", EquipmentType.RING),
							Slot("ring_right", EquipmentType.RING),
						];
	}
}

EquipmentType equipTypeByName(string name)
{
	switch(name)
	{
		case "melee": return EquipmentType.MELEE;
		case "ranged": return EquipmentType.RANGED;
		case "ammo": return EquipmentType.AMMO;
		case "body": return EquipmentType.BODY;
		case "head": return EquipmentType.HEAD;
		case "hands": return EquipmentType.HANDS;
		case "feet": return EquipmentType.FEET;
		case "cloak": return EquipmentType.CLOAK;
		case "amulet": return EquipmentType.AMULET;
		case "ring": return EquipmentType.RING;

		default:
	}

	assert(false);
}
